文章目录
前言一、RISC-V汇编语言简介汇编语言的优缺点
二、汇编语言语法介绍三、RISC-V汇编指令总览RISC-V 汇编指令操作对象RISC-V 汇编指令分类RISC-V 汇编伪指令
四、RISC-V 汇编指令详解算术运算指令(Arithmetic Instructions)逻辑运算指令(Arithmetic Instructions)移位运算指令(Arithmetic Instructions)内存读写指令(Load and Store Instructions)无条件跳转指令
五、编译工具的介绍1.编译器2.汇编器3.链接器4.加载器
总结
前言
之前简单的讲过了RISC-V指令集,接下来我将简单的介绍一下RISC-V的汇编。更直观的去了解,C语言程序如何一步步变成机器语言并让机器执行程序。
提示:以下是本篇文章正文内容,下面案例可供参考
一、RISC-V汇编语言简介
汇编语言(Assembly Language)是一种“低级”语言,直接接触最底层的硬件,需要对底层硬件非常熟悉才能编写出高效的汇编程序。并且汇编语言属于第二代计算机语言,用一些容易理解和记忆的字母,单词来代替一个特定的指令。因此在汇编语言中,用助记符代替机器指令的操作码,用地址符号或标号代替指令或操作数的地址。比如:用“ADD”代表数字逻辑上的加减,“ MOV”代表数据传递等等。 C语言程序在翻译成可以在计算机上运行的机器语言程序,大致需要四个步骤。
首先将高级语言程序编译成汇编语言程序然后用机器语言组装成目标模块链接器将多个模块与库程序组合在一起以解析所有引用最后加载器将机器代码放入适当的存储器位置以供处理器执行
注:所有程序不一定严格按照这个四个步骤执行。为了加快转换过程,可以跳过或将一些步骤组合到一起。一些编译器直接生成目标模块,一些系统使用链接加载器执行最后两个步骤。为了识别文件类型,UNIX遵循文件的后缀约定:C源文件命名为x.c,汇编文件命名为x.s,目标文件命名为x.o,静态链接库程序为x.a,动态链接库路径为x.so,以及默认情况下,可执行文件称为a.out。MS-DOS使用后缀.C、.ASM、.OBJ、.LIB、.DLL和 .EXE的效果相同。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210704121039527.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4OTE1MzU0,size_16,color_FFFFFF,t_70)
汇编语言的优缺点
汇编语言的缺点:
难读难写难移植 汇编语言的优点
灵活强大 汇编语言的应用场景
会要直接访问底层硬件的地方需要对性能执行极致优化的地方
二、汇编语言语法介绍
一个完整的 RISC-V 汇编程序有多条 语句 (statement) 组成。一条典型的 RISC-V 汇编 语句 由 3 部分组成:[ label:][ operation] [ comment]
label(标号): GNU汇编中,任何以冒号结尾的标识符都被认为是一个标号。表示当前指令的位置标记。operation 可以有以下多种类型:
instruction(指令): 直接对应二进制机器指令的字符串。例如addi指令、lw指令等。pseudo-instruction(伪指令): 为了提高编写代码的效率,可以用一 条伪指令指示汇编器产生多条实际的指令(instructions)。directive(指示/伪操作): , 通过类似指令的形式(以“.”开头),通知汇 编器如何控制代码的产生等,不对应具体的指令。macro:采用 .macro/.endm 自定义的宏 comment(注释): 常用方式,“#” 开始到当前行结束。
三、RISC-V汇编指令总览
RISC-V 汇编指令操作对象
寄存器:
32个通用寄存器,x0 ~ x31(注意:仅涉及 RV32I 的通用寄存器组);在 RISC-V 中,Hart 在执行算术逻辑运算时所操作的 数据必须直接来自寄存器。 内存:
Hart 可以执行在寄存器和内存之间的数据读写操作;读写操作使用字节(Byte)为基本单位进行寻址;RV32 可以访问最多 2^32 个字节的内存空间。
RISC-V 汇编指令分类
RISC-V汇编指令分类主要有以下几种:算术运算指令、逻辑运算指令、位移运算指令、内存读写指令、分支与跳转指令。如下图所示,汇编语言的操作与指令是一一对应的,汇编程序可以很简单快速的翻译成机器指令。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210704152340689.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4OTE1MzU0,size_16,color_FFFFFF,t_70)
RISC-V 汇编伪指令
伪指令是由多个汇编指令组成 注:【参考 1】:The RISC-V Instruction Set Manual,Volume I: Unprivileged ISA, Document Version 20191213
四、RISC-V 汇编指令详解
上图中已经显示了汇编中主要的分类,这里我们将更加具体的讲解每一类汇编指令。更加有助于理解,RISC-V 汇编。
算术运算指令(Arithmetic Instructions)
ADD:寄存器与寄存器的加法运算 对应的RISC-V的指令集 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210704155857603.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4OTE1MzU0,size_16,color_FFFFFF,t_70) SUB:寄存器与寄存器的减法运算 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210704195105974.png) ADDI:寄存器与立即数的加法运算 注:(1)imm (12): “immediate”, 立即数占 12 位 (2)在参与算术运算前该 immediate 会被 “符号扩展” 为一个 32 位的数 (3)这个立即数可以表达的数值范围为:[-2^11 , +2^11),即[-2048, 2047)。 LUI:寄存器存放一个32 bits 的高20位的立即数。 注:LUI 指令会构造一个 32 bits 的立即数,这个立即 数的高 20 位对应指令中的 imm,低 12 位清零。 这个立即数作为结果存放在 RD 中。 在统基础(五)之RISC-V指令集中有关于此处的讲解。 LI:是一个伪指令,汇编器会根据 IMM 的实际情况自动生成正确的真实指令。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210704202922132.png) AUIPC:寄存器存放一个32 bits 的高20位的立即数。 注:构造一个 32 bits 的立即数,这个立即数的高 20 位对应指令中 的 imm,低 12 位清零。但和 LUI 不同的是, AUIPC 会先将这个立即数和 PC 值相加,将相加 后的结果存放在 RD 中。 LA:伪指令,常用于加载一个函数或者变量的地址 注:具体编程时给出需要加载的 label,编译器会根据实 际情况利用 auipc 和其他指令自动生成正确的指令 序列。 其他伪指令 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210704210907109.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4OTE1MzU0,size_16,color_FFFFFF,t_70) 算术运算指令总览 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210704210650357.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4OTE1MzU0,size_16,color_FFFFFF,t_70)
逻辑运算指令(Arithmetic Instructions)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210704211426310.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4OTE1MzU0,size_16,color_FFFFFF,t_70) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210704211541547.png)
移位运算指令(Arithmetic Instructions)
逻辑移位 算术移位
内存读写指令(Load and Store Instructions)
内存读写指令分为两类:
内存读指令:Load,将数据从内存读入寄存器内存写指令:Store,将数据从寄存器写出到内存
内存读指令 内存写(Store)
无条件跳转指令
JAL:用于调用子过程(跳转的范围是1MB)
子过程的地址计算方法:首先对 20 bits 宽的 IMM x 2 后进行 符号扩展(sign-extended),然后将符号扩展后的值和 PC 的值相加。因此该函数跳转的范围是以 PC 为基准,上下~+/- 1MB。JAL 指令的下一条指令的地址写入 RD,保存为返回地址。实际编程时,用 label 给出跳转的目标,具体 IMM 值由编译器和 链接器最终负责生成。
JALR用于调用子过程(跳转的范围是2KB)
子过程的地址计算方法:首先对 12 bits 宽的 IMM 进行 sign- extended,然后将符号扩展后的值和 RS1 的值相加,得到最终的 结果后将其最低位设置为 0(确保地址按 2 字节对齐)。因此该函 数跳转的范围是以 RS1 为基准,上下~+/- 2KBJALR 指令的下一条指令的地址写入 RD,保存为返回地址。
无条件跳转的伪指令 如果跳转后不需要返回,可以利用 x0 代替 JAL 和 JALR 中的 RD
五、编译工具的介绍
1.编译器
2.汇编器
3.链接器
4.加载器
总结
注:未完待续!!!!
|